﻿using System.Collections.Concurrent;
using System.Reflection;
using System.Threading.Channels;
using Google.Protobuf;
using Proto;
using Serilog;

namespace MoonFramework.Net
{
    public class MessageBlock
    {
        public BaseConnection sender;
        public IMessage message;
    }

    /// <summary>
    /// 生产消费者多线程消息队列
    /// </summary>
    public class MessageRouter : BaseManager<MessageRouter>
    {
        private readonly Channel<MessageBlock> messageChannel = Channel.CreateUnbounded<MessageBlock>();

        private readonly ConcurrentDictionary<string, Action<BaseConnection, object>> messageMap = new();
        private CancellationTokenSource threadEvent;
        private int workCount;
        public bool Running { get; private set; }

        // 订阅消息处理器
        public void Subscribe<T>(Action<BaseConnection, T> handler) where T : IMessage
        {
            var type = typeof(T).FullName;
            //TODO:配置发送
        }

        // 退订消息处理器
        public void Remove<T>(Action<BaseConnection, T> handler) where T : IMessage
        {
            var type = typeof(T).FullName;
            if (messageMap.TryGetValue(type, out var existing))
            {
                existing -= (sender, msg) => handler(sender, (T)msg);
                if (existing == null)
                {
                    messageMap.TryRemove(type, out _);
                }
                else
                {
                    messageMap[type] = existing;
                }
            }
        }
        
        // 触发消息处理
        private void Fire<T>(BaseConnection sender, T message)
        {
            // var type = typeof(T).FullName;
            // if (message is UserLoginRequest request)
            // {
            //     Log.Debug("{0}  {1}", request.UserName, request.Password);
            // }
            //TODO:处理消息字典的回调
        }

        // 添加新的消息到队列中
        public void SendMessage(BaseConnection sender, IMessage message)
        {
            if (!messageChannel.Writer.TryWrite(new MessageBlock { sender = sender, message = message }))
            {
                // 处理写入失败的情况，例如记录日志或采取其他措施
            }
        }

        // 开启消息处理
        public void Start(int threadCount = 8)
        {
            if (Running) return;
            Running = true;
            threadCount = Math.Clamp(threadCount, 1, 200);
            threadEvent = new CancellationTokenSource();
            var threadToken = threadEvent.Token;
            // 启动消费者线程
            for (var i = 0; i < threadCount; i++)
            {
                Task.Run(() => ConsumerThread(threadToken), threadToken);
            }
        }

        // 消费者线程
        private async Task ConsumerThread(CancellationToken threadToken)
        {
            Interlocked.Increment(ref workCount);
            try
            {
                while (await messageChannel.Reader.WaitToReadAsync(threadToken))
                {
                    while (messageChannel.Reader.TryRead(out var block))
                    {
                        AutoFireMessage(block.sender, block.message);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                //TODO: 处理取消操作，例如记录日志或清理资源
            }
            finally
            {
                Interlocked.Decrement(ref workCount);
            }
        }

        // 递归处理消息
        private void AutoFireMessage(BaseConnection sender, IMessage message)
        {
            Fire(sender, message);

            // 递归处理嵌套的 IMessage 类型的属性
            var type = message.GetType();
            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (property.PropertyType.GetInterface(nameof(IMessage)) != null)
                {
                    if (property.GetValue(message) is IMessage nestedMessage)
                    {
                        AutoFireMessage(sender, nestedMessage);
                    }
                }
            }
        }

        // 停止消息处理
        public async Task Stop()
        {
            if (!Running) return;
            Running = false;
            threadEvent?.Cancel();
            while (workCount > 0)
            {
                await Task.Delay(50);
            }
            messageChannel.Writer.Complete();
        }
    }
}
